package juc.util;

import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 读写锁:
 *      读锁，共享锁
 *      写锁：独占锁
 * 互斥情况：读写，写读，写写互斥
 * 使用场景:在读多于写的情况下，读写锁能够提供比排它锁更好的并发性和吞吐量。
 */
public class ReadWriteLockTest {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch downLatch = new CountDownLatch(1);
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(10);
        Table table = new Table();
        for (int i = 0; i < 100; i++) {
            final int num = i;
            executorService.execute(() -> {
                try {
                    downLatch.await();
                    table.append(String.valueOf(num));
                    //int sleepMills = ThreadLocalRandom.current().nextInt(1000);
                    //Thread.sleep(sleepMills);
                    table.get();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

        downLatch.countDown();
        TimeUnit.SECONDS.sleep(5);
        table.cheack();
        executorService.shutdown();
    }

    static class Table {
        private StringBuffer stringBuffer = new StringBuffer();
        private StringBuilder stringBuilder = new StringBuilder();
        // 获取读写锁
        private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
        // 读锁
        private ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
        // 写锁
        private ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();

        public void append(String value) {
            // 写操作上锁
            writeLock.lock();
            try {
                stringBuilder.append(value);
                stringBuffer.append(value);
            } finally {
                writeLock.unlock();
            }
        }

        public String get() {
            // 读操作上锁
            readLock.lock();
            try {
                System.out.println(ThreadUtil.name()+"stringBuffer==>" + stringBuffer.toString());
                String string = stringBuilder.toString();
                System.out.println(ThreadUtil.name()+"stringBuilder=>"+string);
                return string;
            } finally {
                readLock.unlock();
            }
        }

        /**
         * 检查
         *
         * @return
         */
        public void cheack() {
            String bufferString = stringBuffer.toString();
            System.out.println("stringBuffer==>" + bufferString);
            String builderString = stringBuilder.toString();
            System.out.println("stringBuilder==>" + builderString);
            System.out.println("检查正确性:"+bufferString.equals(builderString));
        }
    }

}
